package hotairballoon.shape.classic;

import graph.Point;
import hotairballoon.exception.OutOfRangeException;
import hotairballoon.shape.Shape;

/***
 * Creates a balloon shape from three costruction points: PRS.
 * @author malpka
 *
 */
public class ClassicShapeConstructor {

    // ksztalt balonu
    private PRS _prs = new PRS();

    // pola pomocnicze biorace udzial w obliczaniu balonu
    private double _minXValue = 0;
    private double _maxXValue = 0;
    private double _circleRadius = 0;


    /***
     * Wyznacza probki ksztaltu balonu.
     * Dane wejsciowe:             PRS - punkty konstrukcyjne balonu
     *                  numberOfPoints - liczba probek ksztaltu
     * Dane wyjsciowe: shape
     * @param numberOfPoints
     */
    public Shape recalculateShape(PRS prs, int numberOfPoints){
        
        Shape shape = new Shape();

        _prs = prs;
        _minXValue = _prs.getR().getX();
        _circleRadius = Math.sqrt(Math.pow(_prs.getP().getX()-_prs.getS().getX(), 2) + Math.pow(_prs.getP().getY()-_prs.getS().getY(), 2));
        _maxXValue = _prs.getS().getX() + _circleRadius;

        shape.clearShape();
        
        double deltaX = (_maxXValue - _prs.getP().getX())/(numberOfPoints-2);

        // pierwszy punkt to punkt dla x=minXValue
        double x = _minXValue;
        try{
            double y = getYValue(x);
            shape.addShapePoint(new Point(x,y));
        }
        catch(OutOfRangeException ex){
            ex.printStackTrace();
        }


        // reszta punktow to okrag
        boolean cont = true;
        x = _prs.getP().getX();
        while(cont){
            try{
                double y = getYValue(x);
                shape.addShapePoint(new Point(x,y));
            }
            catch(OutOfRangeException ex){
                //ex.printStackTrace();
                // punkt x jest poza obszarem balonu.
                // dodajemy ostatni punkt jako
                shape.addShapePoint(new Point(x - deltaX,0));
                cont = false;
            }

            // zwiekszamy x o jeden krok
            x += deltaX;
        }
        return shape;
    }

//    /***
//     * Wyznacza ksztalt brytu balonu.
//     * @param prs
//     * @param goreNumber
//     * @param numberOfPoints
//     * @return
//     */
//    public Shape getGoreShape(PRS prs, ConstructionFactors constructionFactors, int numberOfPoints){
//
//        Shape goreShape = new Shape();
//
//        // ustawiamy zmienne poczatowe (ksztalt balonu)
//        _prs = prs;
//        _minXValue = _prs.Rx;
//        _circleRadius = Math.sqrt(Math.pow(_prs.Px-_prs.Sx, 2) + Math.pow(_prs.Py-_prs.Sy, 2));
//        _maxXValue = _prs.Sx + _circleRadius;
//
//        double dx = (_maxXValue - _minXValue)/(numberOfPoints-2);
//
//        double lastX = _minXValue;
//        double lastY = 0;
//        
//        try{
//            lastY = getYValue(lastX);
//        }
//        catch(OutOfRangeException ex){
//            ex.printStackTrace();
//        }
//
//        double length = 0;
//        double x = _minXValue + dx;
//
//
//        boolean cont = true;
//        while(cont){
//            // punkt y ksztaltu balonu
//            double y = 0;
//
//            try{
//                y = getYValue(lastX);
//            }
//            catch(OutOfRangeException ex){
//               // ex.printStackTrace();
//                //goreShape.addShapePoint(new ShapePoint(x - dx,0));
//                x -= dx;
//                try{
//                    y = getYValue(x);
//                }catch(OutOfRangeException ex2){
//                    ex2.printStackTrace();
//                }
//                cont = false;
//            }
//
//            // wyznaczamy odleglosc miedzy punktami
//            length += Math.sqrt(Math.pow(x - lastX, 2) + Math.pow(y - lastY, 2));
//            lastX = x;
//            lastY = y;
//
//            // aby wyznaczyc szerokosc brytu dla punktu x, nalezy policzyc
//            // obwod okregu o promieniu y (przekroj balonu jest okregiem)
//            // i podzielic ten obwod przez liczbe brytow
//            double width = 2 * Math.PI * y / constructionFactors.goreNumber;
//
//            // dodajemy nowy punkt ksztaltu brytu
//            goreShape.addShapePoint(new ShapePoint(length, width/2));
//
//            x += dx;
//            
//        }
//        
//        return goreShape;
//    }

    private double getYValue(double x) throws OutOfRangeException{
        double y = 0;

        if(x < _minXValue || x > _maxXValue){
            throw new OutOfRangeException();
        }
        else
            if(x <= _prs.getP().getX() && x >= _minXValue){
                y = x*_prs.getP().getY()/_prs.getP().getX();
            }
            else
                if((x <= _prs.getS().getX() + _circleRadius) && (x >= _prs.getP().getX())){

                    y = Math.sqrt(Math.pow(_circleRadius, 2) - Math.pow(x-_prs.getS().getX(), 2)) + _prs.getS().getY();
                    //System.out.println(" y = " + y);
                    if(Double.isNaN(y)){
                        //System.out.println(" y = Nan");
                        y = _prs.getS().getY();
                    }
                }
        //System.out.println("x=" + x + " y=" + y);

        return y;
    }
} 